package com.doodle.common.drawable;

import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.widget.ImageView;

import com.doodle.common.data.AsyncResource;
import com.doodle.common.data.DataAdapter;
import com.doodle.common.utils.ThreadPool;

import java.lang.ref.WeakReference;
import java.util.ArrayList;

public abstract class AsyncDrawable extends TransitionDrawable {
	
	private static final int ANIM_DURATION = 250;
	
	private final Drawable mEmptyDrawable; 
	private final AsyncDrawableResource mDrawable;
	
	private final int mId;
	private final DataAdapter.DataLoadedListener mListener;
	
	private ArrayList<WeakReference<TransitionDrawable>> mCopies;

	public AsyncDrawable(AsyncResource.JobExecutor<Drawable> jobExecutor, Drawable placeHolder, int id, DataAdapter.DataLoadedListener listener) {
		super(new Drawable[] {
				placeHolder == null ? new ColorDrawable(Color.TRANSPARENT) : placeHolder,
				new ColorDrawable(Color.TRANSPARENT)
				});
		setId(0, 0);
		setId(1, 1);
		mEmptyDrawable = getDrawable(1);
		mDrawable = new AsyncDrawableResource(jobExecutor);
		mId = id;
		mListener = listener;
	}

	public void startLoad() {
		mDrawable.startLoad();
	}

	public void cancelLoad() {
		mDrawable.cancelLoad();
	}
	
	public void recycle() {
		mDrawable.recycle();
	}
	
	public boolean isReady() {
		return mDrawable.get() != null;
	}

	public boolean isRequestInProgress() {
		return mDrawable.isRequestInProgress();
	}
	
	public int getLoadState() {
		return mDrawable.getState();
	}

	public boolean isRecycled() {
		return mDrawable.isRecycled();
	}

	protected abstract ThreadPool.Job<Drawable> requestDrawable();
	protected abstract void recycleDrawable(Drawable drawable);
	
	protected void onDrawableLoaded(Drawable drawable) {
		if (mListener != null) {
			mListener.onDataLoaded(mId);
		}
	}
	
	public void setToImageViewSafe(ImageView imageView) {
		Drawable.Callback cb = getCallback();
		if (cb != null && cb != imageView) {
			Drawable layer1 = getDrawable(1);
			if (layer1 == mEmptyDrawable) {
				imageView.setImageDrawable(makeCopy());
			} else {
				imageView.setImageDrawable(layer1.getConstantState().newDrawable());
			}
		} else {
			imageView.setImageDrawable(this);
		}
	}
	
	public Drawable makeCopy() {
		if (mCopies == null) {
			mCopies = new ArrayList<WeakReference<TransitionDrawable>>();
		}
		TransitionDrawable td = (TransitionDrawable)getConstantState().newDrawable();
		mCopies.add(new WeakReference<TransitionDrawable>(td));
		return td;
	}
	
	private class AsyncDrawableResource extends AsyncResource<Drawable> {

		public AsyncDrawableResource(JobExecutor<Drawable> jobExecutor) {
			super(jobExecutor);
		}

		@Override
		public ThreadPool.Job<Drawable> requestResource() {
			return requestDrawable();
		}

		@Override
		public void onLoadFinished(Drawable resource) {
			if (resource != null) {
				setDrawableByLayerId(1, resource);
				startTransition(ANIM_DURATION);
			} else {
				setDrawableByLayerId(1, mEmptyDrawable);
			}
			if (mCopies != null) {
				for (int i = mCopies.size() - 1; i >= 0; --i) {
					WeakReference<TransitionDrawable> r = mCopies.get(i);
					TransitionDrawable td = r.get();
					if (td != null) {
						if (resource != null) {
							td.setDrawableByLayerId(1, resource.getConstantState().newDrawable());
							td.startTransition(ANIM_DURATION);
						} else {
							td.setDrawableByLayerId(1, mEmptyDrawable);
						}
					} else {
						mCopies.remove(i);
					}
				}
			}
			onDrawableLoaded(resource);
		}

		@Override
		protected void recycleResource(Drawable resource) {
			recycleDrawable(resource);
			if (getDrawable(1) != mEmptyDrawable) {
				setDrawableByLayerId(1, mEmptyDrawable);
			}
		}
	};
}
